#pragma once

#include <iostream>
#include <assert.h>
#include "vector.h"
#include <cmath>
namespace math
{
	// 前置声明
	template <typename T, std::size_t N>
	class Vector;

	template <typename Derived, typename T, std::size_t N>
	class VectorExpr
	{
	public:
		Derived const &derived() const
		{
			return static_cast<Derived const &>(*this);
		}
		// 通过 CRTP 调用派生类的 operator()
		T operator[](size_t i) const
		{
			return derived()(i);
		}
	};
	// 两个向量相加获得的新向量
	template <typename LHS, typename RHS, typename T, std::size_t N>
	class VAddExpr : public VectorExpr<VAddExpr<LHS, RHS, T, N>, T, N>
	{
		LHS const &lhs;
		RHS const &rhs;

	public:
		VAddExpr(LHS const &l, RHS const &r) : lhs(l), rhs(r) {}
		T operator()(std::size_t n) const
		{
			return lhs(n) + rhs(n);
		}
	};

	template <typename LHS, typename RHS, typename T, std::size_t N>
	VAddExpr<LHS, RHS, T, N> operator+(
		const VectorExpr<LHS, T, N> &lhs,
		const VectorExpr<RHS, T, N> &rhs)
	{
		return VAddExpr<LHS, RHS, T, N>(lhs.derived(), rhs.derived());
	}

	template <typename LHS, typename RHS, typename T, std::size_t N>
	class VMulExpr : public VectorExpr<VMulExpr<LHS, RHS, T, N>, T, N>
	{
		LHS const &lhs;
		RHS const &rhs;

	public:
		VMulExpr(LHS const &l, RHS const &r) : lhs(l), rhs(r) {}
		T operator()(std::size_t n) const
		{
			return lhs(n) * rhs(n);
		}
	};

	// 两个向量相乘获得的新向量
	template <typename LHS, typename RHS, typename T, std::size_t N>
	VMulExpr<LHS, RHS, T, N> operator*(
		const VectorExpr<LHS, T, N> &lhs,
		const VectorExpr<RHS, T, N> &rhs)
	{
		return VMulExpr<LHS, RHS, T, N>(lhs.derived(), rhs.derived());
	}

	template <typename HS, typename T, std::size_t N>
	class VAgainstExpr : public VectorExpr<VAgainstExpr<HS, T, N>, T, N>
	{
		HS const &hs;

	public:
		VAgainstExpr(HS const &hs) : hs(hs) {}
		T operator()(std::size_t n) const
		{
			return -hs(n);
		}
	};

	// 两个向量相乘获得的新向量
	template <typename HS, typename T, std::size_t N>
	VAgainstExpr<HS, T, N> operator-(
		const VectorExpr<HS, T, N> &hs)
	{
		return VAgainstExpr<HS, T, N>(hs.derived());
	}


	template <typename HS, typename T, std::size_t N>
	class VTMULExpr : public VectorExpr<VTMULExpr<HS, T, N>, T, N>
	{
		HS const &hs;

	public:
		VTMULExpr(HS const &hs) : hs(hs) {}
		T operator()(std::size_t n,T f) const
		{
			return hs(n)*f;
		}
	};

	template <typename T, std::size_t N>
	Vector<T, N> abs(const Vector<T, N> &v)
	{
		Vector<T, N> result;
		for (int i = 0; i < N; i++)
		{
			result[i] = std::abs(v[i]);
		}
		return result;
	}

	template <typename T, std::size_t N>
	T dot(const Vector<T, N> &v1, const Vector<T, N> &v2)
	{
		T result;
		for (int i = 0; i < N; i++)
		{
			result += v1[i] * v2[i];
		}
		return result;
	}

	template <typename T>
	T cross(const Vector<T, 2> &v1, const Vector<T, 2> &v2)
	{
		return v1[0] * v2[1] - v1[1] * v2[0];
	}

	// 可以使用表达式模板实现
	template <typename T>
	inline Vector<T, 3> cross(const Vector<T, 3> &v1, const Vector<T, 3> &v2)
	{
		T v1x = v1[0], v1y = v1[1], v1z = v1[2];
		T v2x = v2[0], v2y = v2[1], v2z = v2[2];
		return Vector<T, 3>{
			v1y * v2z - v1z * v2y,
			v1z * v2x - v1x * v2z,
			v1x * v2y - v1y * v2x};
	}

	template <typename T, std::size_t N>
	inline T lengthSquared(const Vector<T, N> &v)
	{
		T sum = 0.0;
		for (int i = 0; i < N; i++)
		{
			sum += v[i] * v[i];
		}
		return sum;
	}

	template <typename T, std::size_t N>
	inline T length(const Vector<T, N> &v)
	{
		return std::sqrt(lengthSquared(v));
	}

	// 可以使用表达式模板实现
	template <typename T, std::size_t N>
	inline Vector<T, N> normalize(const Vector<T, N> &v)
	{
		Vector<T, N> result;
		for (int i = 0; i < N; i++)
		{
			result[i] = v[i] / length(v);
		}
		return result;
	}

	template <typename E,typename T, std::size_t N>
	inline Vector<T,N> from_expr(const VectorExpr<E, T, N> &expr)
	{
		Vector<T,N> result;
		for (size_t i = 0; i < N; ++i)
		{
			result[i] = expr[i];
		}
		return result;
	}
	
}
